﻿using mozhi.smarterp.Finance.Accounts;
using mozhi.smarterp.Finance.Accounts.Repository;
using mozhi.smarterp.Finance.Basedatas.Customers;
using mozhi.smarterp.Finance.Basedatas.Events;
using mozhi.smarterp.Finance.Basedatas.Repository;
using mozhi.smarterp.Finance.Basedatas.Suppliers;
using mozhi.smarterp.Finance.Enums;
using mozhi.smarterp.Finance.Querys;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Guids;
using Volo.Abp.ObjectMapping;

namespace mozhi.smarterp.Finance.Basedatas
{
    public class SupplierAppService : BaseDataAppService<Supplier, SupplierDto, SupplierCreateDto, SupplierUpdateDto>, ISupplierAppService
    {
        private IAccountRepository _accountRepository;

        public SupplierAppService(IAccountRepository accountRepository, IServiceProvider serviceProvider) :
            base(serviceProvider , ModuleCodeType.Supplier)
        {
            _accountRepository = accountRepository;
        }

        public override async Task<PagedResultDto<SupplierDto>> FindAsync(PageQuery query)
        {
            var result = await base.FindAsync(query);

            var suppliers = result.Items.ToList();

            if (suppliers == null || suppliers.Count == 0)
                return result;

            await LoadAccountInfoAsync(suppliers);

            return result;
        }

        public override async Task<SupplierDto> CreateAsync(SupplierCreateDto dto)
        {
            await Validate(null, dto.Code, dto.Name);

            await ValidateAccount(dto.PayableAccountId, dto.PrepaymentAccountId);

            var supplier = new Supplier(_guidGenerator.Create(), dto.Code, dto.Name, dto.PayableAccountId, dto.PrepaymentAccountId);

            supplier = await _repository.InsertAsync(supplier);

            await _operationLogManager.LogAsync(ModuleCodeType.Supplier, Enums.OperationType.Add, supplier, null);

            return ObjectMapper.Map<Supplier, SupplierDto>(supplier);
        }

        public override async Task<SupplierDto> UpdateAsync(SupplierUpdateDto dto)
        {
            var supplier = await _repository.GetAsync(dto.Id);

            if (supplier == null)
                throw new UserFriendlyException("供应商不存在", "100000");

            var oldSupplier = ObjectMapper.Map<Supplier, SupplierDto>(supplier);

            await Validate(dto.Id, dto.Code, dto.Name);

            await ValidateAccount(dto.PayableAccountId, dto.PrepaymentAccountId);

            supplier.Change(dto.Code, dto.Name, dto.Activated);
            supplier.ChangeAccount(dto.PayableAccountId, dto.PrepaymentAccountId);

            supplier = await _repository.UpdateAsync(supplier);

            var result = ObjectMapper.Map<Supplier, SupplierDto>(supplier);

            await LoadAccountInfoAsync(new List<SupplierDto>() { result });

            await _operationLogManager.LogAsync(ModuleCodeType.Supplier, Enums.OperationType.Update, oldSupplier, result);

            return result;
        }

        public override async Task<SupplierDto> DeleteAsync(Guid id)
        {
            var supplier = await base.DeleteAsync(id);

            await _distributedEventBus.PublishAsync(new DataAssociationRemoveEvent(id , supplier.PayableAccountId));
            await _distributedEventBus.PublishAsync(new DataAssociationRemoveEvent(id, supplier.PrepaymentAccountId));

            return supplier;
        }


        #region
        private async Task LoadAccountInfoAsync(List<SupplierDto> suppliers)
        {
            var accountIds = suppliers.Where(x => x.PayableAccountId != default).Select(x => x.PayableAccountId).ToList();

            accountIds.AddRange(suppliers.Where(x => x.PrepaymentAccountId != default).Select(x => x.PrepaymentAccountId).ToList());

            accountIds = accountIds.Distinct().ToList();

            if (accountIds.Count == 0)
                return;

            var accounts = await _accountRepository.FindAsync(new AccountQuery() { Ids = accountIds });

            foreach (var supplier in suppliers)
            {
                supplier.PayableAccountName = accounts.FirstOrDefault(x => x.Id == supplier.PayableAccountId)?.FullName;
                supplier.PrepaymentAccountName = accounts.FirstOrDefault(x => x.Id == supplier.PrepaymentAccountId)?.FullName;
            }
        }


        private async Task ValidateAccount(Guid payableAccountId, Guid prepaymentAccountId)
        {
            var accounts = await _accountRepository.FindAsync(new AccountQuery() { Ids = new List<Guid> { payableAccountId, prepaymentAccountId } });

            var matchPayableAccount = accounts.FirstOrDefault(x => x.Id == payableAccountId);

            base.ValidateAccount(matchPayableAccount, "应付科目");

            var matchPrepaymentAccount = accounts.FirstOrDefault(x => x.Id == prepaymentAccountId);

            base.ValidateAccount(matchPrepaymentAccount, "预付科目");
        }
        #endregion
    }
}
